package NG::Sys::Cached::List::Object;
use strict;
use warnings;
use utf8;

use NG::Sys::Cached::Common;
our @ISA = qw(NG::Sys::Cached::Common::Child);

sub obj_id {
	my ($self) = @_;
	return $self->{id};
}
sub list_keys {
	my $self = shift;
	my $data = $self->{parent}->_read_data($self);
	return [ keys %{$data->[3]} ];
}
sub list {
	my $self = shift;
	my $data = $self->{parent}->_read_data($self);
	return $data->[0];
}
sub list_objects {
	my $self = shift;
	my $list = shift || $self->list;
	my $class = $self->{parent}{record_class};
	my $ekey = $self->{parent}{ekey};
	return [ map {$class->new($_,$self,$_->{$ekey})} @$list ];
}
sub make_object {
	my $self = shift;
	my $row = shift;
	return $self->{parent}{record_class}->new($row,$self);
}
sub get_by_entry {
	my $self = shift;
	my $entry = shift;
	unless(defined $entry){
		die "not defined entry";
	}
	my $data = $self->{parent}->_read_data($self);
	if(defined(my $pos = $data->[1]{$entry})){
		return $self->{parent}{record_class}->new($data->[0][$pos],$self);
	}
	return undef;
}
sub get_by_pos {
	my $self = shift;
	my $pos = shift;
	my $data = $self->{parent}->_read_data($self);
	return $self->{parent}{record_class}->new($data->[0][$pos],$self);
}
sub get_first {
	my $self = shift;
	my $data = $self->{parent}->_read_data($self);
	return $self->{parent}{record_class}->new($data->[0][0],$self);
}
sub get_last {
	my $self = shift;
	my $data = $self->{parent}->_read_data($self);
	return $self->{parent}{record_class}->new($data->[0][-1],$self);
}
sub get_by_key {
	my $self = shift;
	my $key = shift;
	my $need_object = shift;
	my $data = $self->{parent}->_read_data($self);
	my $list = [ @{$data->[0]}[@{$data->[3]{$key} || []}] ];
	if($need_object){
		return $self->list_objects($list);
	}else{
		return $list;
	}
}
sub length {
	my $self = shift;
	my $data = $self->{parent}->_read_data($self);
	if(@_){
		return scalar @{$data->[3]{$_[0]} || []};
	}else{
		return $data->[2];
	}
}
sub summary {
	my $self = shift;
	my $data = $self->{parent}->_summary($self);
	return $data;
}
sub filter {
	my $self = shift;
	my $filter_hash = shift;
	my $need_object = shift;
	my $data = $self->{parent}->_read_data($self);
	my @filter_list = grep {
			$self->{parent}->check_field($_) && defined $filter_hash->{$_}
		} keys %$filter_hash;
	my @result;
	M:
	for my $row(@{$data->[0]}){
		for(@filter_list){
			unless(defined $row->{$_} and $row->{$_} eq $filter_hash->{$_}){
				next M;
			}
		}
		push @result,$row;
	}
	return $need_object ? $self->list_objects(\@result) : \@result;
}
sub insert {
	my $self = shift;
	my $row = shift;
	if($self->{readonly}){
		die "update readonly data\n";
	}
	if($self->{transaction}){
		push @{$self->{transaction}},[0,$row];
		return 0;
	}else{
		return $self->{parent}->_update_data($self,[0,$row]);
	}
}
sub remove {
	my $self = shift;
	if($self->{readonly}){
		die "update readonly data\n";
	}
	$self->{parent}->_remove_data($self);
}
sub begin_transaction {
	my $self = shift;
	if($self->{readonly}){
		die "update readonly data\n";
	}
	if($self->{transaction}){
		return 0;
	}else{
		return $self->{transaction} = [];
	}
}
sub has_transaction {
	my $self = shift;
	if($self->{transaction}){
		return 1;
	}else{
		return 0;
	}
}
sub commit {
	my $self = shift;
	unless($self->{transaction}){
		return 0;
	}elsif(@{$self->{transaction}}){
		return $self->{parent}->_update_data($self, list => delete $self->{transaction});
	}else{
		delete $self->{transaction};
		return 0;
	}
}
sub rollback {
	my $self = shift;
	unless($self->{transaction}){
		return 0;
	}else{
		delete $self->{transaction};
		return 1;
	}
}
sub update_data {
	my $self = shift;
	if($self->{readonly}){
		die "update readonly data\n";
	}
	my ($rec,$key,$val) = @_;
	if($self->{transaction}){
		push @{$self->{transaction}},[$rec->entry,$key,$val];
		return $val;
	}else{
		return $self->{parent}->_update_data($self,[$rec->entry,$key,$val]);
	}
}
sub dump {
	my $self = shift;
	my $data = $self->{parent}->_read_data($self);
	require Data::Dumper;
	return Data::Dumper::Dumper($data);
}
1;
